home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Mail / pine3.92 / pico / line.c < prev    next >
C/C++ Source or Header  |  1996-03-14  |  18KB  |  741 lines

  1. #if    !defined(lint) && !defined(DOS)
  2. static char rcsid[] = "$Id: line.c,v 4.16 1996/03/15 07:41:11 hubert Exp $";
  3. #endif
  4. /*
  5.  * Program:    Line management routines
  6.  *
  7.  *
  8.  * Michael Seibel
  9.  * Networks and Distributed Computing
  10.  * Computing and Communications
  11.  * University of Washington
  12.  * Administration Builiding, AG-44
  13.  * Seattle, Washington, 98195, USA
  14.  * Internet: mikes@cac.washington.edu
  15.  *
  16.  * Please address all bugs and comments to "pine-bugs@cac.washington.edu"
  17.  *
  18.  *
  19.  * Pine and Pico are registered trademarks of the University of Washington.
  20.  * No commercial use of these trademarks may be made without prior written
  21.  * permission of the University of Washington.
  22.  * 
  23.  * Pine, Pico, and Pilot software and its included text are Copyright
  24.  * 1989-1996 by the University of Washington.
  25.  * 
  26.  * The full text of our legal notices is contained in the file called
  27.  * CPYRIGHT, included with this distribution.
  28.  *
  29.  */
  30. /*
  31.  * The functions in this file are a general set of line management utilities.
  32.  * They are the only routines that touch the text. They also touch the buffer
  33.  * and window structures, to make sure that the necessary updating gets done.
  34.  * There are routines in this file that handle the kill buffer too. It isn't
  35.  * here for any good reason.
  36.  *
  37.  * Note that this code only updates the dot and mark values in the window list.
  38.  * Since all the code acts on the current window, the buffer that we are
  39.  * editing must be being displayed, which means that "b_nwnd" is non zero,
  40.  * which means that the dot and mark values in the buffer headers are nonsense.
  41.  */
  42.  
  43. #include        <stdio.h>
  44. #include    "osdep.h"
  45. #include    "pico.h"
  46. #include    "estruct.h"
  47. #include        "edef.h"
  48. #include        "efunc.h"
  49.  
  50. #define NBLOCK    16                      /* Line block chunk size        */
  51. #define KBLOCK  1024                    /* Kill buffer block size       */
  52.  
  53.  
  54. /*
  55.  * Struct to manage the kill and justify buffers
  56.  */
  57. struct pkchunk {
  58.     short        used;        /* # of bytes used in this buffer*/
  59.     char        bufp[KBLOCK];    /* buffer containing text        */
  60.     struct pkchunk *next;        /* pointer to next chunk     */
  61. };
  62.  
  63. static struct pkbuf {
  64.     long        total;        /* # of bytes used in buffer     */
  65.     struct pkchunk *first;        /* first one of these in the chain */
  66.     struct pkchunk *last;        /* last one of these in the chain */
  67. } *kbufp, *fbufp;
  68.  
  69.  
  70. #ifdef    ANSI
  71.     int insspace(int, int);
  72.     int ldelnewline(void);
  73.     int pkbufdel(struct pkbuf **);
  74.     void pkchunkdel(struct pkchunk **);
  75.     int pkbufinsert(int, struct pkbuf **);
  76.     int pkbufremove(int, struct pkbuf *);
  77. #else
  78.     int insspace();
  79.     int ldelnewline();
  80.     int pkbufdel();
  81.     void pkchunkdel();
  82.     int pkbufinsert();
  83.     int pkbufremove();
  84. #endif
  85.  
  86.  
  87. /*
  88.  * This routine allocates a block of memory large enough to hold a LINE
  89.  * containing "used" characters. The block is always rounded up a bit. Return
  90.  * a pointer to the new block, or NULL if there isn't any memory left. Print a
  91.  * message in the message line if no space.
  92.  */
  93. LINE    *
  94. lalloc(used)
  95. register int    used;
  96. {
  97.     register LINE   *lp;
  98.     register int    size;
  99.  
  100.     size = (used+NBLOCK-1) & ~(NBLOCK-1);
  101.     if (size == 0)                          /* Assume that an empty */
  102.       size = NBLOCK;                  /* line is for type-in. */
  103.  
  104.     if ((lp = (LINE *) malloc(sizeof(LINE)+(size*sizeof(CELL)))) == NULL) {
  105.     emlwrite("Cannot allocate %d bytes", (void *)size);
  106.     return (NULL);
  107.     }
  108.  
  109.     lp->l_size = size;
  110.     lp->l_used = used;
  111.     return (lp);
  112. }
  113.  
  114. /*
  115.  * Delete line "lp". Fix all of the links that might point at it (they are
  116.  * moved to offset 0 of the next line. Unlink the line from whatever buffer it
  117.  * might be in. Release the memory. The buffers are updated too; the magic
  118.  * conditions described in the above comments don't hold here.
  119.  */
  120. lfree(lp)
  121. register LINE   *lp;
  122. {
  123.     register BUFFER *bp;
  124.     register WINDOW *wp;
  125.  
  126.     wp = wheadp;
  127.     while (wp != NULL) {
  128.     if (wp->w_linep == lp)
  129.       wp->w_linep = lp->l_fp;
  130.  
  131.     if (wp->w_dotp  == lp) {
  132.         wp->w_dotp  = lp->l_fp;
  133.         wp->w_doto  = 0;
  134.     }
  135.  
  136.     if (wp->w_markp == lp) {
  137.         wp->w_markp = lp->l_fp;
  138.         wp->w_marko = 0;
  139.     }
  140.  
  141.     wp = wp->w_wndp;
  142.     }
  143.  
  144.     bp = bheadp;
  145.     while (bp != NULL) {
  146.     if (bp->b_nwnd == 0) {
  147.         if (bp->b_dotp  == lp) {
  148.         bp->b_dotp = lp->l_fp;
  149.         bp->b_doto = 0;
  150.         }
  151.  
  152.         if (bp->b_markp == lp) {
  153.         bp->b_markp = lp->l_fp;
  154.         bp->b_marko = 0;
  155.         }
  156.     }
  157.  
  158.     bp = bp->b_bufp;
  159.     }
  160.  
  161.     lp->l_bp->l_fp = lp->l_fp;
  162.     lp->l_fp->l_bp = lp->l_bp;
  163.     free((char *) lp);
  164. }
  165.  
  166.  
  167. /*
  168.  * This routine gets called when a character is changed in place in the current
  169.  * buffer. It updates all of the required flags in the buffer and window
  170.  * system. The flag used is passed as an argument; if the buffer is being
  171.  * displayed in more than 1 window we change EDIT t HARD. Set MODE if the
  172.  * mode line needs to be updated (the "*" has to be set).
  173.  */
  174. lchange(flag)
  175. register int    flag;
  176. {
  177.     register WINDOW *wp;
  178.  
  179.     if (curbp->b_nwnd != 1)                 /* Ensure hard.         */
  180.       flag = WFHARD;
  181.  
  182.     if ((curbp->b_flag&BFCHG) == 0) {       /* First change, so     */
  183.     if(Pmaster == NULL)
  184.       flag |= WFMODE;                 /* update mode lines.   */
  185.     curbp->b_flag |= BFCHG;
  186.     }
  187.  
  188.     wp = wheadp;
  189.     while (wp != NULL) {
  190.     if (wp->w_bufp == curbp)
  191.       wp->w_flag |= flag;
  192.     wp = wp->w_wndp;
  193.     }
  194. }
  195.  
  196.  
  197. /*
  198.  * insert spaces forward into text
  199.  * default flag and numeric argument 
  200.  */
  201. insspace(f, n)    
  202. int f, n;
  203. {
  204.     linsert(n, ' ');
  205.     backchar(f, n);
  206. }
  207.  
  208. /*
  209.  * Insert "n" copies of the character "c" at the current location of dot. In
  210.  * the easy case all that happens is the text is stored in the line. In the
  211.  * hard case, the line has to be reallocated. When the window list is updated,
  212.  * take special care; I screwed it up once. You always update dot in the
  213.  * current window. You update mark, and a dot in another window, if it is
  214.  * greater than the place where you did the insert. Return TRUE if all is
  215.  * well, and FALSE on errors.
  216.  */
  217. linsert(n, c)
  218. int n, c;
  219. {
  220.     register LINE   *dotp;
  221.     register int     doto;
  222.     register WINDOW *wp;
  223.  
  224.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  225.       return(rdonly());    /* we are in read only mode    */
  226.  
  227.     dotp = curwp->w_dotp;
  228.     doto = curwp->w_doto;
  229.     lchange(WFEDIT);
  230.  
  231.     if(!geninsert(&(curwp->w_dotp), &(curwp->w_doto), curbp->b_linep,
  232.                   c, (curwp->w_markp) ? 1 : 0, n, &curbp->b_linecnt))
  233.       return(FALSE);
  234.  
  235.     wp = wheadp;                /* Update windows       */
  236.     while (wp != NULL) {
  237.     if (wp->w_linep == dotp)
  238.       wp->w_linep = wp->w_dotp;
  239.  
  240.     if (wp->w_imarkp == dotp) {        /* added for internal mark */
  241.         wp->w_imarkp = wp->w_dotp;
  242.         if (wp->w_imarko > doto)
  243.           wp->w_imarko += n;
  244.     }
  245.  
  246.     if (wp->w_markp == dotp) {
  247.         wp->w_markp = dotp;
  248.         if (wp->w_marko > doto)
  249.           wp->w_marko += n;
  250.     }
  251.     wp = wp->w_wndp;
  252.     }
  253.  
  254.     return (TRUE);
  255. }
  256.  
  257.  
  258. /*
  259.  * geninsert - do the actual work of inserting a character into
  260.  *             the list of lines.
  261.  */
  262. int
  263. geninsert(dotp, doto, linep, c, attb, n, lines)
  264. LINE **dotp, *linep;
  265. short *doto;
  266. int    c, attb, n;
  267. long  *lines;
  268. {
  269.     register LINE  *lp1;
  270.     register LINE  *lp2;
  271.     register CELL  *cp1;
  272.     register CELL  *cp2;
  273.     CELL ac;
  274.  
  275.     ac.a = attb;
  276.     if (*dotp == linep) {            /* At the end: special  */
  277.     if (*doto != 0) {
  278.         emlwrite("Programmer botch: geninsert", NULL);
  279.         return (FALSE);
  280.     }
  281.  
  282.     if ((lp1=lalloc(n)) == NULL)        /* Allocate new line    */
  283.       return (FALSE);
  284.  
  285.     lp2 = (*dotp)->l_bp;                /* Previous line        */
  286.     lp2->l_fp = lp1;                /* Link in              */
  287.     lp1->l_fp = *dotp;
  288.     (*dotp)->l_bp = lp1;
  289.     lp1->l_bp = lp2;
  290.     *doto = n;
  291.     *dotp = lp1;
  292.     ac.c  = ((char)c & 0xff);
  293.     cp1   = &(*dotp)->l_text[0];
  294.         while(n--)
  295.       *cp1++ = ac;
  296.  
  297.     if(lines)
  298.       (*lines)++;
  299.  
  300.     return (TRUE);
  301.     }
  302.  
  303.     if ((*dotp)->l_used+n > (*dotp)->l_size) {      /* Hard: reallocate     */
  304.     if ((lp1=lalloc((*dotp)->l_used+n)) == NULL)
  305.       return (FALSE);
  306.  
  307.     cp1 = &(*dotp)->l_text[0];
  308.     cp2 = &lp1->l_text[0];
  309.     while (cp1 != &(*dotp)->l_text[*doto])
  310.       *cp2++ = *cp1++;
  311.  
  312.     cp2 += n;
  313.     while (cp1 != &(*dotp)->l_text[(*dotp)->l_used])
  314.       *cp2++ = *cp1++;
  315.  
  316.     (*dotp)->l_bp->l_fp = lp1;
  317.     lp1->l_fp = (*dotp)->l_fp;
  318.     (*dotp)->l_fp->l_bp = lp1;
  319.     lp1->l_bp = (*dotp)->l_bp;
  320.  
  321.     /* global may be keeping track of mark/imark */
  322.     if(wheadp){
  323.         if (wheadp->w_imarkp == *dotp)
  324.           wheadp->w_imarkp = lp1;
  325.  
  326.         if (wheadp->w_markp == *dotp)
  327.           wheadp->w_markp = lp1;
  328.     }
  329.  
  330.     free((char *) (*dotp));
  331.     *dotp = lp1;
  332.     } else {                                /* Easy: in place       */
  333.     (*dotp)->l_used += n;
  334.     cp2 = &(*dotp)->l_text[(*dotp)->l_used];
  335.     cp1 = cp2-n;
  336.     while (cp1 != &(*dotp)->l_text[*doto])
  337.       *--cp2 = *--cp1;
  338.     }
  339.  
  340.     ac.c = ((char)c & 0xff);
  341.     while(n--)                    /* add the chars */
  342.       (*dotp)->l_text[(*doto)++] = ac;
  343.  
  344.     return(TRUE);
  345. }
  346.  
  347.  
  348. /*
  349.  * Insert a newline into the buffer at the current location of dot in the
  350.  * current window. The funny ass-backwards way it does things is not a botch;
  351.  * it just makes the last line in the file not a special case. Return TRUE if
  352.  * everything works out and FALSE on error (memory allocation failure). The
  353.  * update of dot and mark is a bit easier then in the above case, because the
  354.  * split forces more updating.
  355.  */
  356. lnewline()
  357. {
  358.     register CELL   *cp1;
  359.     register CELL   *cp2;
  360.     register LINE   *lp1;
  361.     register LINE   *lp2;
  362.     register int    doto;
  363.     register WINDOW *wp;
  364.  
  365.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  366.       return(rdonly());    /* we are in read only mode    */
  367.  
  368.     lchange(WFHARD);
  369.     lp1  = curwp->w_dotp;                   /* Get the address and  */
  370.     doto = curwp->w_doto;                   /* offset of "."        */
  371.     if ((lp2=lalloc(doto)) == NULL)         /* New first half line  */
  372.       return (FALSE);
  373.  
  374.     cp1 = &lp1->l_text[0];                  /* Shuffle text around  */
  375.     cp2 = &lp2->l_text[0];
  376.     while (cp1 != &lp1->l_text[doto])
  377.       *cp2++ = *cp1++;
  378.  
  379.     cp2 = &lp1->l_text[0];
  380.     while (cp1 != &lp1->l_text[lp1->l_used])
  381.       *cp2++ = *cp1++;
  382.  
  383.     lp1->l_used -= doto;
  384.     lp2->l_bp = lp1->l_bp;
  385.     lp1->l_bp = lp2;
  386.     lp2->l_bp->l_fp = lp2;
  387.     lp2->l_fp = lp1;
  388.     wp = wheadp;                            /* Windows              */
  389.     while (wp != NULL) {
  390.     if (wp->w_linep == lp1)
  391.       wp->w_linep = lp2;
  392.  
  393.     if (wp->w_dotp == lp1) {
  394.         if (wp->w_doto < doto)
  395.           wp->w_dotp = lp2;
  396.         else
  397.           wp->w_doto -= doto;
  398.     }
  399.  
  400.     if (wp->w_imarkp == lp1) {          /* ADDED for internal mark */
  401.         if (wp->w_imarko < doto)
  402.           wp->w_imarkp = lp2;
  403.         else
  404.           wp->w_imarko -= doto;
  405.     }
  406.  
  407.     if (wp->w_markp == lp1) {
  408.         if (wp->w_marko < doto)
  409.           wp->w_markp = lp2;
  410.         else
  411.           wp->w_marko -= doto;
  412.     }
  413.     wp = wp->w_wndp;
  414.     }
  415.  
  416.     /*
  417.      * Keep track of the number of lines in the buffer.
  418.      */
  419.     ++curbp->b_linecnt;
  420.     return (TRUE);
  421. }
  422.  
  423.  
  424. /*
  425.  * This function deletes "n" bytes, starting at dot. It understands how do deal
  426.  * with end of lines, etc. It returns TRUE if all of the characters were
  427.  * deleted, and FALSE if they were not (because dot ran into the end of the
  428.  * buffer. The "kflag" is TRUE if the text should be put in the kill buffer.
  429.  */
  430. ldelete(n, kflag)
  431. long n;
  432. int kflag;
  433. {
  434.     register CELL   *cp1;
  435.     register CELL   *cp2;
  436.     register LINE   *dotp;
  437.     register int    doto;
  438.     register int    chunk;
  439.     register WINDOW *wp;
  440.  
  441.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  442.       return(rdonly());    /* we are in read only mode    */
  443.  
  444.     while (n != 0) {
  445.     dotp = curwp->w_dotp;
  446.     doto = curwp->w_doto;
  447.     if (dotp == curbp->b_linep)     /* Hit end of buffer.   */
  448.       return (FALSE);
  449.     chunk = dotp->l_used-doto;      /* Size of chunk.       */
  450.     if (chunk > n)
  451.       chunk = n;
  452.     if (chunk == 0) {               /* End of line, merge.  */
  453.         lchange(WFHARD);
  454.         if (ldelnewline() == FALSE
  455.         || (kflag!=FALSE && kinsert('\n')==FALSE))
  456.           return (FALSE);
  457.         --n;
  458.         continue;
  459.     }
  460.  
  461.     lchange(WFEDIT);
  462.     cp1 = &dotp->l_text[doto];      /* Scrunch text.        */
  463.     cp2 = cp1 + chunk;
  464.     if (kflag != FALSE) {           /* Kill?                */
  465.         while (cp1 != cp2) {
  466.         if (kinsert(cp1->c) == FALSE)
  467.           return (FALSE);
  468.         ++cp1;
  469.         }
  470.         cp1 = &dotp->l_text[doto];
  471.     }
  472.  
  473.     while (cp2 != &dotp->l_text[dotp->l_used])
  474.       *cp1++ = *cp2++;
  475.  
  476.     dotp->l_used -= chunk;
  477.     wp = wheadp;                    /* Fix windows          */
  478.     while (wp != NULL) {
  479.         if (wp->w_dotp==dotp && wp->w_doto>=doto) {
  480.         wp->w_doto -= chunk;
  481.         if (wp->w_doto < doto)
  482.           wp->w_doto = doto;
  483.         }
  484.  
  485.         if (wp->w_markp==dotp && wp->w_marko>=doto) {
  486.         wp->w_marko -= chunk;
  487.         if (wp->w_marko < doto)
  488.           wp->w_marko = doto;
  489.         }
  490.  
  491.         if (wp->w_imarkp==dotp && wp->w_imarko>=doto) {
  492.         wp->w_imarko -= chunk;
  493.         if (wp->w_imarko < doto)
  494.           wp->w_imarko = doto;
  495.         }
  496.  
  497.         wp = wp->w_wndp;
  498.     }
  499.     n -= chunk;
  500.     }
  501.  
  502.     return (TRUE);
  503. }
  504.  
  505. /*
  506.  * Delete a newline. Join the current line with the next line. If the next line
  507.  * is the magic header line always return TRUE; merging the last line with the
  508.  * header line can be thought of as always being a successful operation, even
  509.  * if nothing is done, and this makes the kill buffer work "right". Easy cases
  510.  * can be done by shuffling data around. Hard cases require that lines be moved
  511.  * about in memory. Return FALSE on error and TRUE if all looks ok. Called by
  512.  * "ldelete" only.
  513.  */
  514. ldelnewline()
  515. {
  516.     register CELL   *cp1;
  517.     register CELL   *cp2;
  518.     register LINE   *lp1;
  519.     register LINE   *lp2;
  520.     register LINE   *lp3;
  521.     register WINDOW *wp;
  522.  
  523.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  524.       return(rdonly());    /* we are in read only mode    */
  525.  
  526.     lp1 = curwp->w_dotp;
  527.     lp2 = lp1->l_fp;
  528.     if (lp2 == curbp->b_linep) {            /* At the buffer end.   */
  529.     if (lp1->l_used == 0) {             /* Blank line.          */
  530.         lfree(lp1);
  531.         --curbp->b_linecnt;
  532.     }
  533.  
  534.     return (TRUE);
  535.     }
  536.  
  537.     if (lp2->l_used <= lp1->l_size-lp1->l_used) {
  538.     cp1 = &lp1->l_text[lp1->l_used];
  539.     cp2 = &lp2->l_text[0];
  540.     while (cp2 != &lp2->l_text[lp2->l_used])
  541.       *cp1++ = *cp2++;
  542.  
  543.     wp = wheadp;
  544.     while (wp != NULL) {
  545.         if (wp->w_linep == lp2)
  546.           wp->w_linep = lp1;
  547.         if (wp->w_dotp == lp2) {
  548.         wp->w_dotp  = lp1;
  549.         wp->w_doto += lp1->l_used;
  550.         }
  551.         if (wp->w_markp == lp2) {
  552.         wp->w_markp  = lp1;
  553.         wp->w_marko += lp1->l_used;
  554.         }
  555.         wp = wp->w_wndp;
  556.     }
  557.     lp1->l_used += lp2->l_used;
  558.     lp1->l_fp = lp2->l_fp;
  559.     lp2->l_fp->l_bp = lp1;
  560.     free((char *) lp2);
  561.     --curbp->b_linecnt;
  562.     return (TRUE);
  563.     }
  564.  
  565.     if ((lp3=lalloc(lp1->l_used+lp2->l_used)) == NULL)
  566.       return (FALSE);
  567.  
  568.     cp1 = &lp1->l_text[0];
  569.     cp2 = &lp3->l_text[0];
  570.     while (cp1 != &lp1->l_text[lp1->l_used])
  571.       *cp2++ = *cp1++;
  572.  
  573.     cp1 = &lp2->l_text[0];
  574.     while (cp1 != &lp2->l_text[lp2->l_used])
  575.       *cp2++ = *cp1++;
  576.  
  577.     lp1->l_bp->l_fp = lp3;
  578.     lp3->l_fp = lp2->l_fp;
  579.     lp2->l_fp->l_bp = lp3;
  580.     lp3->l_bp = lp1->l_bp;
  581.     wp = wheadp;
  582.     while (wp != NULL) {
  583.     if (wp->w_linep==lp1 || wp->w_linep==lp2)
  584.       wp->w_linep = lp3;
  585.     if (wp->w_dotp == lp1)
  586.       wp->w_dotp  = lp3;
  587.     else if (wp->w_dotp == lp2) {
  588.         wp->w_dotp  = lp3;
  589.         wp->w_doto += lp1->l_used;
  590.     }
  591.     if (wp->w_markp == lp1)
  592.       wp->w_markp  = lp3;
  593.     else if (wp->w_markp == lp2) {
  594.         wp->w_markp  = lp3;
  595.         wp->w_marko += lp1->l_used;
  596.     }
  597.     wp = wp->w_wndp;
  598.     }
  599.  
  600.     free((char *) lp1);
  601.     free((char *) lp2);
  602.     --curbp->b_linecnt;
  603.     return (TRUE);
  604. }
  605.  
  606.  
  607. /*
  608.  * Delete all of the text saved in the kill buffer. Called by commands when a
  609.  * new kill context is being created. The kill buffer array is released, just
  610.  * in case the buffer has grown to immense size. No errors.
  611.  */
  612. kdelete()
  613. {
  614.     return(pkbufdel(&kbufp));
  615. }
  616.  
  617. fdelete()
  618. {
  619.     return(pkbufdel(&fbufp));
  620. }
  621.  
  622. pkbufdel(buf)
  623.     struct pkbuf **buf;
  624. {
  625.     if (*buf) {
  626.     pkchunkdel(&(*buf)->first);
  627.     free((char *) *buf);
  628.     *buf = NULL;
  629.     }
  630. }
  631.  
  632.  
  633. void
  634. pkchunkdel(chunk)
  635.     struct pkchunk **chunk;
  636. {
  637.     if(chunk){
  638.     if((*chunk)->next)
  639.       pkchunkdel(&(*chunk)->next);
  640.  
  641.     free((char *) *chunk);
  642.     *chunk = NULL;
  643.     }
  644. }
  645.  
  646.  
  647. /*
  648.  * Insert a character to the kill buffer, enlarging the buffer if there isn't
  649.  * any room. Always grow the buffer in chunks, on the assumption that if you
  650.  * put something in the kill buffer you are going to put more stuff there too
  651.  * later. Return TRUE if all is well, and FALSE on errors.
  652.  */
  653. kinsert(c)
  654.     int c;
  655. {
  656.     return(pkbufinsert(c, &kbufp));
  657. }
  658.  
  659. finsert(c)
  660.     int c;
  661. {
  662.     return(pkbufinsert(c, &fbufp));
  663. }
  664.  
  665. pkbufinsert(c, buf)
  666.     int c;
  667.     struct pkbuf **buf;
  668. {
  669.     register char *nbufp;
  670.  
  671.     if(!*buf){
  672.     if(*buf = (struct pkbuf *) malloc(sizeof(struct pkbuf)))
  673.       memset(*buf, 0, sizeof(struct pkbuf));
  674.     else
  675.       return(FALSE);
  676.     }
  677.  
  678.     if((*buf)->total % KBLOCK == 0){
  679.     struct pkchunk *p = (*buf)->last;
  680.     if((*buf)->last = (struct pkchunk *) malloc(sizeof(struct pkchunk))){
  681.         memset((*buf)->last, 0, sizeof(struct pkchunk));
  682.         if(p)
  683.           p->next = (*buf)->last;
  684.         else
  685.           (*buf)->first = (*buf)->last;
  686.     }
  687.     else
  688.       return(FALSE);
  689.     }
  690.  
  691.     (*buf)->last->bufp[(*buf)->last->used++] = c;
  692.     (*buf)->total++;
  693.     return (TRUE);
  694. }
  695.  
  696.  
  697. /*
  698.  * These functions get characters from the requested buffer. If the
  699.  * character index "n" is off the end, it returns "-1". This lets the
  700.  * caller just scan along until it gets a "-1" back.
  701.  */
  702. kremove(n)
  703.     int n;
  704. {
  705.     return(pkbufremove(n, kbufp));
  706. }
  707.  
  708. fremove(n)
  709.     int n;
  710. {
  711.     return(pkbufremove(n, fbufp));
  712. }
  713.  
  714.  
  715. pkbufremove(n, buf)
  716.     int n;
  717.     struct pkbuf *buf;
  718. {
  719.     if(n >= 0 && buf && n < buf->total){
  720.     register struct pkchunk *p = buf->first;
  721.     int             block = n / KBLOCK;
  722.  
  723.     while(block--)
  724.       if(!(p = p->next))
  725.         return(-1);
  726.  
  727.     return(p->bufp[n % KBLOCK] & 0xff);
  728.     }
  729.     else
  730.       return(-1);
  731. }
  732.  
  733.  
  734. /*
  735.  * This function just returns the current size of the kill buffer
  736.  */
  737. ksize()
  738. {
  739.     return(kbufp ? (int) kbufp->total : 0);
  740. }
  741.